package com.probiz.estore.webapp.action;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.ModelAndView;

import com.probiz.estore.common.util.DateUtil;
import com.probiz.estore.core.model.BaseObject;
import com.probiz.estore.framework.test.BaseGenericTransactionalTestCase;

/**
 * 重构为基于范型。在重构中碰到一些奇怪的问题（GenericControllerTestCase<T,C>，C为Controller的时候。）
 * 
 * 
 * @param <T>
 */
public abstract class GenericControllerTestCase<T> extends BaseGenericTransactionalTestCase<T> {
	protected String mappedUrl;

	protected String listView;

	protected String formView;

	/**
	 * 
	 */
	public GenericControllerTestCase() {
		super();
		// 缺省的View设置，注意，页面首字母小写，如system/SystemLanguageList。可以在Bean设置以覆盖。
		String viewPrefix = new StringBuilder(entityClass.getPackage().getName().substring(
				entityClass.getPackage().getName().lastIndexOf(".") + 1)).append("/").append(entityClassName)
				.toString();
		listView = viewPrefix + "List";
		formView = viewPrefix + "Form";
		mappedUrl = "/" + listView + ".html";
	}

	protected MockHttpServletRequest newGet(String url) {
		return new MockHttpServletRequest("GET", url);
	}

	/**
	 * Convenience methods to make tests simpler
	 */
	protected MockHttpServletRequest newPost(String url) {
		return new MockHttpServletRequest("POST", url);
	}

	protected void objectToRequestParameters(Object o, MockHttpServletRequest request) throws Exception {
		objectToRequestParameters(o, request, null);
	}

	protected void objectToRequestParameters(Object o, MockHttpServletRequest request, String prefix) throws Exception {
		Class clazz = o.getClass();
		Field[] fields = getDeclaredFields(clazz);
		AccessibleObject.setAccessible(fields, true);

		for (int i = 0; i < fields.length; i++) {
			Object field = (fields[i].get(o));
			if (field != null) {
				if (field instanceof BaseObject) {
					objectToRequestParameters(field, request, fields[i].getName());
				} else if (!(field instanceof List) && !(field instanceof Set)) {
					String paramName = fields[i].getName();

					if (prefix != null) {
						paramName = prefix + "." + paramName;
					}

					String paramValue = String.valueOf(fields[i].get(o));

					// handle Dates
					if (field instanceof java.util.Date) {
						paramValue = DateUtil.convertDateToString((Date) fields[i].get(o));
						if ("null".equals(paramValue))
							paramValue = "";
					}

					request.addParameter(paramName, paramValue);
				}
			}
		}
	}

	private Field[] getDeclaredFields(Class clazz) {
		Field[] f = new Field[0];
		Class superClazz = clazz.getSuperclass();
		Collection rval = new ArrayList();

		if (superClazz != null) {
			rval.addAll(Arrays.asList(getDeclaredFields(superClazz)));
		}

		rval.addAll(Arrays.asList(clazz.getDeclaredFields()));
		return (Field[]) rval.toArray(f);
	}

	protected void addActionParam(MockHttpServletRequest request, String actionName) {
		request.addParameter("doAction", actionName);
	}

	protected MockHttpServletRequest getRequestOfAction(String actionName) {
		MockHttpServletRequest request = newGet(mappedUrl);
		request.addParameter("doAction", actionName);
		return request;
	}

	protected T getEntityFromModelAndView(ModelAndView mav) {
		return (T) mav.getModel().get(entityClassName);
	}

	protected void assertNoErrors(ModelAndView mav) {
		BindingResult bindingResult = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + entityClassName);

		assertEquals(bindingResult.getErrorCount(), 0);
	}

}
